<template>
  <canvas
    id="canvasDom"
    :width="props.canvasWidth"
    :height="props.canvasHeight"
    @click="drawPic"
  ></canvas>
</template>
<script setup>
  import { onMounted, onBeforeUnmount, computed } from 'vue'
  let props = defineProps({
      canvasWidth: {
        // 容器宽度
        type: Number,
        default: 100
      },
      canvasHeight: {
        // 容器高度
        type: Number,
        default: 40
      },
      refreshTime: {
        //验证码刷新间隔时间
        type: Number,
        default: 60
      }
    }),
    emits = defineEmits(['change']),
    verifyCodeTimeId = null, //定时器id
    randomStr = '0123456789abcdefghijklmnopqrstuvwxyz', // 所有随机字符串
    trueRefreshTime = computed(() => {
      return props.refreshTime * 1000
    }),
    verifyCodeStr = '' //验证码字符串
  onMounted(() => {
    initVerifyCodeImg()
  })
  // 初始化
  const initVerifyCodeImg = () => {
    drawPic()
    verifyCodeTimeId = setInterval(() => {
      drawPic()
    }, trueRefreshTime.value)
  }
  // 绘制验证码图片
  const drawPic = () => {
    randomCode()
    let canvas = document.getElementById('canvasDom')
    let ctx = canvas.getContext('2d')
    ctx.textBaseline = 'bottom'
    // 绘制背景
    ctx.fillStyle = '#e6ecfd'
    ctx.fillRect(0, 0, props.canvasWidth, props.canvasHeight)
    // 绘制文字
    for (let i = 0; i < verifyCodeStr.length; i++) {
      drawText(ctx, verifyCodeStr[i], i)
    }
    drawLine(ctx)
    drawDot(ctx)
  }
  //4个随机字符
  const randomCode = () => {
    verifyCodeStr = ''
    for (let i = 0; i < 4; i++) {
      let txt = randomStr[randomNum(0, randomStr.length)]
      verifyCodeStr += txt
    }
    emits('change', verifyCodeStr)
  }
  // 随机数
  const randomNum = (min, max) => {
    return Math.floor(Math.random() * (max - min) + min)
  }
  // 随机色
  const randomColor = (min, max) => {
    let r = randomNum(min, max)
    let g = randomNum(min, max)
    let b = randomNum(min, max)
    return 'rgb(' + r + ',' + g + ',' + b + ')'
  }
  // 绘制文字
  const drawText = (ctx, txt, i) => {
    let fontSizeMin = 30, // 字体最小值
      fontSizeMax = 40 // 字体最大值
    ctx.fillStyle = randomColor(50, 160) // 随机生成字体颜色
    ctx.font = randomNum(fontSizeMin, fontSizeMax) + 'px SimHei' // 随机生成字体大小
    let x = (i + 1) * (props.canvasWidth / (verifyCodeStr.length + 1))
    let y = randomNum(fontSizeMax, props.canvasHeight - 5)
    var deg = randomNum(-30, 30)
    // 修改坐标原点和旋转角度
    ctx.translate(x, y)
    ctx.rotate((deg * Math.PI) / 180)
    ctx.fillText(txt, 0, 0)
    // 恢复坐标原点和旋转角度
    ctx.rotate((-deg * Math.PI) / 180)
    ctx.translate(-x, -y)
  }
  // 绘制干扰线
  const drawLine = (ctx) => {
    for (let i = 0; i < 4; i++) {
      ctx.strokeStyle = randomColor(100, 200)
      ctx.beginPath()
      ctx.moveTo(
        randomNum(0, props.canvasWidth),
        randomNum(0, props.canvasHeight)
      )
      ctx.lineTo(
        randomNum(0, props.canvasWidth),
        randomNum(0, props.canvasHeight)
      )
      ctx.stroke()
    }
  }
  // 绘制干扰点
  const drawDot = (ctx) => {
    // 绘制干扰点
    for (let i = 0; i < 30; i++) {
      ctx.fillStyle = randomColor(0, 255)
      ctx.beginPath()
      ctx.arc(
        randomNum(0, props.canvasWidth),
        randomNum(0, props.canvasHeight),
        1,
        0,
        2 * Math.PI
      )
      ctx.fill()
    }
  }
  //暴露绘制图片方法供父组件使用
  defineExpose({
    drawPic
  })
  onBeforeUnmount(() => {
    clearInterval(verifyCodeTimeId) //页面销毁前，需要清除定时器
  })
</script>
<style scoped lang="scss">
  #canvasDom {
    cursor: pointer;
  }
</style>
